﻿Imports ICSharpCode.SharpZipLib.Zip
Imports System.IO
Imports System.Runtime.Serialization
Imports System.Xml.Serialization
Imports System.Xml.Linq
Imports System.Linq
Imports BoneSoft.CSS
Imports WebSitePanel.SkinDesigner.Business.Css

Public Class ThemeManager
    Public Shared Sub Cleanup(Optional ByVal ThrowOnFail As Boolean = False)
        If Directory.Exists(Toolbox.TempPath & "TemporaryFiles") Then
            Try
                Directory.Delete(Toolbox.TempPath & "TemporaryFiles", True)
            Catch ex As Exception
                If ThrowOnFail Then
                    Throw
                End If
            End Try
        End If
    End Sub
    Public Shared Sub CreateTheme(ByVal Path As String, ByVal ThemeName As String)
        Cleanup(True)
        Toolbox.CopyDirectory("ThemeTemplates\1.0.2", Toolbox.TempPath & "TemporaryFiles")
        Directory.Move(Toolbox.TempPath & "TemporaryFiles\App_Themes\Default", Toolbox.TempPath & "TemporaryFiles\App_Themes\Theme")
        Directory.Move(Toolbox.TempPath & "TemporaryFiles\App_Skins\Default", Toolbox.TempPath & "TemporaryFiles\App_Skins\Theme")
        Directory.Move(Toolbox.TempPath & "TemporaryFiles\App_Containers\Default", Toolbox.TempPath & "TemporaryFiles\App_Containers\Theme")
        File.WriteAllText(Toolbox.TempPath & "TemporaryFiles\info.txt", ThemeName)
        SaveTheme(Path, ThemeName)
        LoadTheme(Path)
    End Sub
    Public Shared Sub SaveTheme(ByVal Destination As String, ByVal ThemeName As String)
        Dim folder As String = Path.GetDirectoryName(Destination)
        Dim filename As String = Path.GetFileName(Destination)

        Dim ar As List(Of String) = GenerateFileList(Toolbox.TempPath & "TemporaryFiles")
        Dim ostream As FileStream
        Dim obuffer As Byte()
        Dim oZipStream As New ZipOutputStream(File.Create(Destination))
        ' create zip stream
        oZipStream.SetLevel(1)
        ' maximum compression
        Dim oZipEntry As ZipEntry
        Try
            For Each Fil As String In ar
                ' for each file, generate a zipentry
                oZipEntry = New ZipEntry(Fil.Remove(0, Fil.IndexOf("TemporaryFiles\") + 15).Replace("\Theme\", "\" & ThemeName & "\"))
                oZipStream.PutNextEntry(oZipEntry)
                If Not Fil.EndsWith("/") Then
                    ' if a file ends with '/' its a directory
                    ostream = File.OpenRead(Fil)
                    obuffer = New Byte(ostream.Length - 1) {}
                    ostream.Read(obuffer, 0, obuffer.Length)
                    oZipStream.Write(obuffer, 0, obuffer.Length)
                    ostream.Close()
                End If
            Next
        Catch ex As Exception

        Finally
            oZipStream.Finish()
            oZipStream.Close()
        End Try
    End Sub
    Public Shared Function LoadTheme(ByVal SourceFile As String) As String
        Cleanup(True)
        Dim s As New ZipInputStream(File.OpenRead(SourceFile))
        Dim theEntry As ZipEntry = Nothing
        Dim tmpEntry As String = [String].Empty

        While (InlineAssignHelper(theEntry, s.GetNextEntry())) IsNot Nothing
            Dim directoryName As String = Toolbox.TempPath & "TemporaryFiles"
            Dim fileName As String = Path.GetFileName(theEntry.Name)

            ' create directory 
            If directoryName <> "" Then
                Directory.CreateDirectory(directoryName)
            End If
            If fileName <> [String].Empty Then
                If theEntry.Name.IndexOf(".ini") < 0 Then
                    Dim fullPath As String = (directoryName & "\") + theEntry.Name
                    Dim fullDirPath As String
                    fullDirPath = Path.GetDirectoryName(fullPath)
                    If Not Directory.Exists(fullDirPath) Then
                        Directory.CreateDirectory(fullDirPath)
                    End If
                    Dim streamWriter As FileStream = File.Create(fullPath)
                    Dim size As Integer = 2048
                    Dim data As Byte() = New Byte(2047) {}
                    size = s.Read(data, 0, data.Length)
                    Do
                        streamWriter.Write(data, 0, size)
                        size = s.Read(data, 0, data.Length)
                    Loop Until size = 0
                    streamWriter.Close()
                End If
            End If
        End While
        s.Close()
        Dim themename As String = File.ReadAllText(Toolbox.TempPath & "TemporaryFiles\info.txt")
        Directory.Move(Toolbox.TempPath & "TemporaryFiles\App_Themes\" & themename, Toolbox.TempPath & "TemporaryFiles\App_Themes\Theme")
        Directory.Move(Toolbox.TempPath & "TemporaryFiles\App_Skins\" & themename, Toolbox.TempPath & "TemporaryFiles\App_Skins\Theme")
        Directory.Move(Toolbox.TempPath & "TemporaryFiles\App_Containers\" & themename, Toolbox.TempPath & "TemporaryFiles\App_Containers\Theme")
        If Not File.Exists(Toolbox.SettingsPath) Then
            File.WriteAllText(Toolbox.SettingsPath, "<?xml version=""1.0"" encoding=""utf-8"" ?>" & vbCrLf & "<root>" & vbCrLf & vbCrLf & "</root>")
            _xmldoc = XDocument.Load(Toolbox.SettingsPath)
            _cssmanager = New CssManager
            FillSettingsFile()
        Else
            _xmldoc = XDocument.Load(Toolbox.SettingsPath)
        End If
        Return themename
    End Function

    Public Shared Sub ExportTheme(ByVal Destination As String)
        Dim themename As String = File.ReadAllText(Toolbox.TempPath & "TemporaryFiles\info.txt")
        Dim savedir As String = (Destination & "\" & themename).Replace("\\", "\")
        Dim i As Integer = 1
        While Directory.Exists(savedir)
            savedir &= "(" & i & ")"
            i = i + 1
        End While
        Directory.CreateDirectory(savedir)
        Toolbox.CopyDirectory(Toolbox.TempPath & "\TemporaryFiles", savedir, False)
        Directory.Move(savedir & "\App_Themes\Theme", savedir & "\App_Themes\" & themename)
        Directory.Move(savedir & "\App_Skins\Theme", savedir & "\App_Skins\" & themename)
        Directory.Move(savedir & "\App_Containers\Theme", savedir & "\App_Containers\" & themename)
    End Sub
    Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
        target = value
        Return value
    End Function
    Private Shared Function GenerateFileList(ByVal Dir As String) As List(Of String)
        Dim files As New List(Of String)
        files.AddRange(Directory.GetFiles(Dir))
        If files.Count = 0 Then
            files.Add(Dir & "/")
        End If
        For Each dirs As String In Directory.GetDirectories(Dir)
            files.AddRange(GenerateFileList(dirs))
        Next
        Return files
    End Function
#Region "Conversion for old themes"
    Private Shared _cssmanager As CssManager
    Private Shared Sub FillSettingsFile()
        SaveSettingsColor("documentbackgroundcolor", GetCssColorValue(CssFileType.SkinLayout, "BODY", "background-color", Color.White))
        SaveSettingsFont("footerfont", GetFont(CssFileType.SkinLayout, "#Footer"))
        Dim value As String = GetCssValue(CssFileType.SkinLayout, "BODY", "background-repeat", "repeat")
        Dim docbackrepeat As BackgroundRepeat
        Select Case value
            Case "repeat-x"
                docbackrepeat = BackgroundRepeat.RepeatX
            Case "repeat-y"
                docbackrepeat = BackgroundRepeat.RepeatY
            Case "no-repeat"
                docbackrepeat = BackgroundRepeat.NoRepeat
            Case Else
                docbackrepeat = BackgroundRepeat.Repeat
        End Select
        SaveSetting("documentbackgroundrepeat", docbackrepeat.ToString)
        SaveSetting("documentbackgroundimage", GetCssValue(CssFileType.SkinLayout, "BODY", "background-image", ""))
        Dim filename As String = "formbackground.png"
        Dim height As Integer = Toolbox.GetImageHeight(filename)
        Dim color1 As Color = Color.White
        Dim color2 As Color = Color.White
        If height > 0 Then
            color1 = Toolbox.GetImageColor(filename, 0, 0)
            If color1.A = 0 Then
                color1 = Color.Transparent
            End If
            color2 = Toolbox.GetImageColor(filename, 0, height - 1)
            If color2.A = 0 Then
                color2 = Color.Transparent
            End If
        End If
        SaveSettingGradientDefinition("documentbackgroundgradient", New GradientDefinition(color1, color2, height))
        SaveSettingsColor("footerlinkcolor", GetCssColorValue(CssFileType.SkinLayout, "#Footer A", "color", Color.Gray))
        SaveSettingsColor("pagebackgroundcolor", GetCssColorValue(CssFileType.Skin, ".FormButtonsBar", "background", Color.White))
        SaveSetting("pagepadding", GetCssValue(CssFileType.SkinLayout, "#Top", "margin", 1, 1))
        SaveSetting("pageoffset", GetCssValue(CssFileType.SkinLayout, "#SkinLayout", "margin-top", 0))
        SaveSettingsColor("pagebordercolor", GetCssColorValue(CssFileType.SkinLayout, "#SkinContent", "border-color", Color.Black))
        SaveSetting("pageborderwidth", GetCssValue(CssFileType.SkinLayout, "#SkinContent", "border-width", 4).Replace("px", ""))
        SaveSetting("pageborderstyle", GetCssValue(CssFileType.SkinLayout, "#SkinContent", "border-style", "solid"))
        SaveSettingsColor("headercolor", Toolbox.GetImageColor("header_bkg.gif", 0, 0))
        SaveSettingsFont("headerfont", GetFont(CssFileType.SkinLayout, "#Header .Account"))
        SaveSettingsColor("topmenubackgroundcolor", Toolbox.GetImageColor("top_menu_bkg.gif", 0, 1))
        SaveSettingsColor("topmenubackgroundhovercolor", Toolbox.GetImageColor("top_menu__hover_bkg.gif", 0, 15))
        SaveSetting("topmenuheight", GetCssValue(CssFileType.SkinLayout, "#TopMenu", "height", "30"))
        SaveSetting("topmenusplitterwidth", GetCssValue(CssFileType.Menus, ".TopMenu ul.AspNet-Menu li span", "border-right", "1", 1))
        SaveSettingsColor("topmenusplittercolor", GetCssColorValue(CssFileType.Menus, ".TopMenu ul.AspNet-Menu li span", "border-right", Color.Black, 2))
        SaveSetting("topmenutopborderwidth", GetCssValue(CssFileType.SkinLayout, "#TopMenu", "border-top", "1", 1))
        SaveSettingsColor("topmenutopbordercolor", GetCssColorValue(CssFileType.SkinLayout, "#TopMenu", "border-top", Color.Black, 2))
        SaveSetting("topmenubottomborderwidth", GetCssValue(CssFileType.SkinLayout, "#TopMenu", "border-bottom-width", "0"))
        SaveSettingsColor("topmenubottombordercolor", GetCssColorValue(CssFileType.SkinLayout, "#TopMenu", "border-bottom-color", Color.Black))
        SaveSettingsColor("secondarymenubackgroundcolor", GetCssColorValue(CssFileType.SkinLayout, "#Left .Menu", "background-color", Color.White))
        SaveSetting("secondarymenuposition", [Enum].Parse(GetType(Position), GetCssValue(CssFileType.SkinLayout, "#Left", "float", "left"), True))
        SaveSettingsColor("containercolor", Toolbox.GetImageColor("module_header_bkg.gif", 0, 15))
        SaveSettingsColor("breadcrumbbackgroundcolor", GetCssColorValue(CssFileType.SkinLayout, "#Breadcrumb", "background", Color.White))
        SaveSettingsFont("breadcrumbfont", GetFont(CssFileType.SkinLayout, "#Breadcrumb .CurrentNode span.Huge"))
        Dim type As CssFileType = CssFileType.SkinLayout
        Dim selector As String = "#Breadcrumb .Path A"
        Dim breadcrumblinkfont As New CssFont(GetCssValue(type, selector, "font-size", "8"),
                       GetCssValue(type, selector, "font-family", "Tahoma"),
                       GetCssValue(type, selector, "font-weight", "") = "bold",
                       GetCssValue(type, selector, "font-style", "") = "italic",
                       GetCssValue(type, selector, "text-decoration", "underline") = "underline",
                       GetCssColorValue(type, selector, "color", Color.FromArgb(31, 73, 120)))
        SaveSettingsFont("breadcrumblinkfont", breadcrumblinkfont)
    End Sub
    Private Shared Function GetFont(ByVal type As CssFileType, ByVal Selector As String) As CssFont
        Return New CssFont(GetCssValue(type, Selector, "font-size", "8"),
                           GetCssValue(type, Selector, "font-family", "Tahoma"),
                           GetCssValue(type, Selector, "font-weight", "") = "bold",
                           GetCssValue(type, Selector, "font-style", "") = "italic",
                           GetCssValue(type, Selector, "text-decoration", "") = "underline",
                           GetCssColorValue(type, Selector, "color", Color.Black))
    End Function
    Private Shared Function GetCssValue(ByVal Type As CssFileType, ByVal Selector As String, ByVal Declaration As String, ByVal DefaultValue As String, Optional ByVal TermID As Integer = 0) As String
        Dim t As Term = _cssmanager.Files(Type).GetCssValue(Selector, Declaration, TermID)
        If t IsNot Nothing Then
            Return t.Value
        Else
            Return DefaultValue
        End If
    End Function
    Private Shared Function GetCssColorValue(ByVal Type As CssFileType, ByVal Selector As String, ByVal Declaration As String, ByVal DefaultValue As Color, Optional ByVal TermID As Integer = 0) As Color
        Dim t As Term = _cssmanager.Files(Type).GetCssValue(Selector, Declaration, TermID)
        If t IsNot Nothing Then
            Return t.ToColor
        Else
            Return DefaultValue
        End If
    End Function
#End Region
  
#Region "Settings"
    Private Shared _xmldoc As XDocument
    Public Shared Sub SaveSetting(ByVal Key As String, ByVal Value As String)
        Dim keyel As XElement = (From el As XElement In _xmldoc.<root>.Elements Where el.Name = Key).FirstOrDefault
        If keyel Is Nothing Then
            keyel = New XElement(Key)
            _xmldoc.<root>.FirstOrDefault.Add(keyel)
        End If
        keyel.Value = Value
        _xmldoc.Save(Toolbox.SettingsPath)
    End Sub
    Public Shared Function GetSetting(ByVal Key As String, Optional ByVal defaultvalue As String = "") As String
        Dim keyel As XElement = (From el As XElement In _xmldoc.<root>.Elements Where el.Name = Key).FirstOrDefault
        If keyel Is Nothing Then
            Return defaultvalue
        Else
            Return keyel.Value
        End If
    End Function

    Public Shared Function GetSettingsColor(ByVal Key As String, Optional ByVal DefaultColor As String = "#000000") As Color
        Return Toolbox.GetColor(GetSetting(Key, DefaultColor))
    End Function
    Public Shared Function GetSettingsGlowMode(ByVal Key As String, Optional ByVal DefaultGlowMode As GlowMode = GlowMode.Gradient) As GlowMode
        Return [Enum].Parse(GetType(GlowMode), GetSetting(Key, DefaultGlowMode.ToString), True)
    End Function
    Public Shared Function GetSettingsFont(ByVal key As String) As CssFont
        Return New CssFont(GetSetting(key & "fontsize", "8"),
                           GetSetting(key & "fontfamily", "Tahoma"),
                           GetSetting(key & "fontweight", "false"),
                           GetSetting(key & "fontstyle", "false"),
                           GetSetting(key & "textdecoration", "false"),
                           GetSettingsColor(key & "color", "#000000"))
    End Function
    Public Shared Function GetSettingsGradientDefinition(ByVal Key As String) As GradientDefinition
        Return New GradientDefinition(GetSettingsColor(Key & "color1"), GetSettingsColor(Key & "color2"), GetSetting(Key & "height"))
    End Function
    Public Shared Function GetSettingsBackgroundRepeat(ByVal Key As String, Optional ByVal DefaultBackgroundRepeat As BackgroundRepeat = BackgroundRepeat.Repeat) As BackgroundRepeat
        Return [Enum].Parse(GetType(BackgroundRepeat), GetSetting(Key, DefaultBackgroundRepeat.ToString), True)
    End Function

    Public Shared Sub SaveSettingsColor(ByVal Key As String, ByVal Color As Color, Optional ByVal IncludeAlpha As Boolean = False)
        If IncludeAlpha Then
            SaveSetting(Key, Toolbox.GetHexAlphaColor(Color))
        Else
            SaveSetting(Key, Toolbox.GetHexColor(Color))
        End If

    End Sub
    Public Shared Sub SaveSettingsFont(ByVal Key As String, ByVal Font As CssFont)
        SaveSetting(Key & "fontsize", Font.FontSize)
        SaveSetting(Key & "fontfamily", Font.FontFamily)
        SaveSetting(Key & "fontweight", Font.Bold)
        SaveSetting(Key & "fontstyle", Font.Italic)
        SaveSetting(Key & "textdecoration", Font.Underline)
        SaveSetting(Key & "color", Toolbox.GetHexColor(Font.Color))
    End Sub
    Public Shared Sub SaveSettingGradientDefinition(ByVal Key As String, ByVal Gradient As GradientDefinition)
        SaveSettingsColor(Key & "color1", Gradient.Color1, True)
        SaveSettingsColor(Key & "color2", Gradient.Color2, True)
        SaveSetting(Key & "height", Gradient.Height)
    End Sub
#End Region
End Class